Skip to content

Conversation

@Alex-Choi0
Copy link
Collaborator

@Alex-Choi0 Alex-Choi0 commented Apr 26, 2025

요구사항

기본

로그인

  • 이메일 input에서 focus out 할 때, 값이 없을 경우 input에 빨강색 테두리와 아래에 "이메일을 입력해주세요." 빨강색 에러 메세지를 보입니다.
  • 이메일 input에서 focus out 할 때, 이메일 형식에 맞지 않는 경우 input에 빨강색 테두리와 아래에 "잘못된 이메일 형식입니다" 빨강색 에러 메세지를 보입니다.
  • 비밀번호 input에서 focus out 할 때, 값이 없을 경우 아래에 "비밀번호를 입력해주세요." 에러 메세지를 보입니다
  • 비밀번호 input에서 focus out 할 때, 값이 8자 미만일 경우 아래에 "비밀번호를 8자 이상 입력해주세요." 에러 메세지를 보입니다.
  • input 에 빈 값이 있거나 에러 메세지가 있으면 '로그인' 버튼은 비활성화 됩니다.
  • input 에 유효한 값을 입력하면 '로그인' 버튼이 활성화 됩니다.
  • 활성화된 '로그인' 버튼을 누르면 "/items" 로 이동합니다

회원가입

  • 이메일 input에서 focus out 할 때, 값이 없을 경우 input에 빨강색 테두리와 아래에 "이메일을 입력해주세요." 빨강색 에러 메세지를 보입니다.
  • 이메일 input에서 focus out 할 때, 이메일 형식에 맞지 않는 경우 input에 빨강색 테두리와 아래에 "잘못된 이메일 형식입니다" 빨강색 에러 메세지를 보입니다.
  • 닉네임 input에서 focus out 할 때, 값이 없을 경우 input에 빨강색 테두리와 아래에 "닉네임을 입력해주세요." 빨강색 에러 메세지를 보입니다.
  • 비밀번호 input에서 focus out 할 때, 값이 없을 경우 아래에 "비밀번호를 입력해주세요." 에러 메세지를 보입니다
  • 비밀번호 input에서 focus out 할 때, 값이 8자 미만일 경우 아래에 "비밀번호를 8자 이상 입력해주세요." 에러 메세지를 보입니다.
  • 비밀번호 input과 비밀번호 확인 input의 값이 다른 경우, 비밀번호 확인 input 아래에 "비밀번호가 일치하지 않습니다.." 에러 메세지를 보입니다.
  • input 에 빈 값이 있거나 에러 메세지가 있으면 '회원가입' 버튼은 비활성화 됩니다.
  • input 에 유효한 값을 입력하면 '회원가입' 버튼이 활성화 됩니다.
  • 활성화된 '회원가입' 버튼을 누르면 로그인 페이지로 이동합니다

심화

  • 눈 모양 아이콘 클릭시 비밀번호의 문자열이 보이기도 하고, 가려지기도 합니다.
  • 비밀번호의 문자열이 가려질 때는 눈 모양 아이콘에는 사선이 그어져있고, 비밀번호의 문자열이 보일 때는 사선이 없는 눈 모양 아이콘이 보이도록 합니다.

스크린샷

image

image

image

image

image

웹사이트 링크

Link

멘토에게

  • 자바스크립트를 추가하고 나서 HTML, CSS, JavaScript 코드가 더 복잡해지고 지저분해지고 있습니다. 현재는 어느정도 처리가 가능하지만 향후 개발에서 기능이 추가되서 더욱 복잡해질때 리팩토링을 어떻게 진행하는지 궁금합니다.
  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@addiescode-sj

@Alex-Choi0 Alex-Choi0 changed the title Basic 최재호 sprint4 [최재호] sprint4 Apr 26, 2025
@Alex-Choi0 Alex-Choi0 added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Apr 27, 2025
@addiescode-sj addiescode-sj self-requested a review April 29, 2025 09:06
Copy link
Collaborator

@addiescode-sj addiescode-sj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다!
하나의 함수가 너무 많은 일을 하지않도록 작업 단위를 쪼개는것부터 리팩토링 시작해보시면 좋을것같아요. 단계별로 어떻게 리팩토링하면될지 error.js에 자세히 예시를 들어드렸으니 참고해보세요!

주요 리뷰 포인트

  • 유지보수를 고려한 개발

@@ -0,0 +1,106 @@
export function ErrorCheck(code, data = "") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일반적으로 함수 네이밍은 파스칼케이스를 사용하지않고, 동사로 시작합니다 :)

Suggested change
export function ErrorCheck(code, data = "") {
export function checkError(code, data = "") {

아래 아티클 참고해보시면 도움이 되실것같아요!
참고


const inputBorder = "2px solid red"

if (code == "email") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if문 중첩이 있어서 가독성이 많이 떨어지고, 하나의 함수가 관여하는일이 너무 많아서 유지보수가 어려워보입니다.

이 두가지를 해결하기위해서는 함수가 단일 책임을 가질수있도록 분리해보시는게 좋습니다.

우선 이런 방식은 어떨까요?

// 공통 스타일 정의
const errorStyle = {
  color: "red",
  fontSize: "20px",
  marginTop: "1px",
  display: "block",
};

const successStyle = {
  color: "",
  fontSize: "",
  marginTop: "",
};

const errorBorder = "2px solid red";
const successBorder = "";

// 유효성 검사 함수들
const validateEmail = (email) => {
  if (!email) {
    return {
      error: true,
      message: "이메일을 입력해주세요",
    };
  }

  const regex = /^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$/;
  const isValid = regex.test(email);

  return {
    error: !isValid,
    message: isValid ? "" : "잘못된 이메일 형식 입니다.",
  };
};

const validatePassword = (password) => {
  if (!password) {
    return {
      error: true,
      message: "비밀번호를 입력해주세요.",
    };
  }

  const isValid = password.length > 8;
  return {
    error: !isValid,
    message: isValid ? "" : "비밀번호를 8자 이상 입력해주세요.",
  };
};

const validateNickname = (nickname) => {
  const isValid = nickname.length >= 1;
  return {
    error: !isValid,
    message: isValid ? "" : "닉네임을 입력해주세요.",
  };
};

const validatePasswordCheck = (passwords) => {
  const isValid = passwords.password1 === passwords.password2;
  return {
    error: !isValid,
    message: isValid ? "" : "비밀번호가 일치하지 않습니다",
  };
};

// 메인 함수
export function checkError(code, data = "") {
  let validationResult;

  switch (code) {
    case "email":
      validationResult = validateEmail(data);
      break;
    case "password":
      validationResult = validatePassword(data);
      break;
    case "nickname":
      validationResult = validateNickname(data);
      break;
    case "passwordCheck":
      validationResult = validatePasswordCheck(data);
      break;
    default:
      return {
        error: false,
        message: "",
        messageStyle: successStyle,
        inputBorder: successBorder,
      };
  }

  return {
    error: validationResult.error,
    message: validationResult.message,
    messageStyle: validationResult.error ? errorStyle : successStyle,
    inputBorder: validationResult.error ? errorBorder : successBorder,
  };
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 함수가 한번에 하나의 일을 할 수 있게끔 쪼개고 보니,
유효성 검사를 수행할때도 각각 따로 함수를 만들 필요가 없어보이고, 재사용 가능한 단위로 분리하는것이 가능해보입니다.

그렇다면 유효성 검사를 수행할때 재사용을 고려해 좀 더 통합적으로 관리될수있도록 만들어볼까요?

코드 예시를 들어드릴게요!

  • 유효성 검사를 담당하는 validation.js
// validation.js - 검증 로직
export const validators = {
  email: (value) => {
    if (!value) return { isValid: false, message: '이메일을 입력해주세요' };
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
      return { isValid: false, message: '올바른 이메일 형식이 아닙니다' };
    }
    return { isValid: true, message: '' };
  },
  
  nickname: (value) => {
    if (!value) return { isValid: false, message: '닉네임을 입력해주세요' };
    return { isValid: true, message: '' };
  },
  
  password: (value) => {
    if (!value) return { isValid: false, message: '비밀번호를 입력해주세요' };
    if (value.length < 8) {
      return { isValid: false, message: '비밀번호는 8자 이상이어야 합니다' };
    }
    return { isValid: true, message: '' };
  },
  
  passwordCheck: (value, formValues) => {
    if (!value) return { isValid: true, message: '' }; // 빈 값은 허용
    if (value !== formValues.password) {
      return { isValid: false, message: '비밀번호가 일치하지 않습니다' };
    }
    return { isValid: true, message: '' };
  }
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 방식은

이렇게 validation을 통합적으로 담당하는 객체를 만들고, checkError 함수에서는 이런식으로 사용해준다면

export function checkError(type, data = "") {
  const validator = validators[type];
  if (!validator) {
    return {
      error: false,
      message: "",
      messageStyle: successStyle,
      inputBorder: successBorder,
    };
  }

  const result = validator(data);
  return {
    error: !result.isValid,
    message: result.message,
    messageStyle: !result.isValid ? errorStyle : successStyle,
    inputBorder: !result.isValid ? errorBorder : successBorder,
  };
}

개별적으로 다른 유효성 검사를 수행하던 함수들을 없애주고, switch case문도 사용하지않게 되니까 코드양이 훨씬 줄어들고, 읽기 수월해지고, 수정 및 확장에 용이해지고, 코드가 간결해지겠죠?


passwordLabel.parentNode.insertBefore(warningMessage1, passwordLabel)

emailInput.addEventListener("focusout", (e) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 함수도 위에서 얘기했던것처럼 하나의 함수가 너무 많은 일을 담당하고있어요.

  • validation 상태에 따른 UI 업데이트하기
  • 입력 필드 초기 상태 설정하기
  • 이벤트 핸들러 연결하기

세가지 함수로 작업을 쪼개서 리팩토링해볼까요?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서도 login.js에서 드린 코멘트 참고해주세요 :)

@addiescode-sj addiescode-sj merged commit 4093a90 into codeit-bootcamp-frontend:Basic-최재호 May 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants